package com.xtf.mutids.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xtf.mutids.cache.DataBaseNumCache;
import com.xtf.mutids.constant.DataSourceTypeConstant;
import com.xtf.mutids.datasource.DynamicDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.yaml.snakeyaml.Yaml;

import javax.sql.DataSource;
import java.io.InputStream;
import java.util.*;

@Slf4j
@Configuration
public class BeanConfiguration {
    private DruidDataSource initDruidDataSource(JSONObject properties) {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername(properties.getString("username"));
        druidDataSource.setUrl(properties.getString("url"));
        druidDataSource.setPassword(properties.getString("password"));
        return druidDataSource;
    }

    @Bean
    public DynamicDataSource dataSource() {
        Map<Object, Object> targetDataSources = buildTargetDataSourcesMap();
        return new DynamicDataSource(targetDataSources);
    }

    private Map<Object, Object> buildTargetDataSourcesMap() {
        JSONObject properties;
        Map<Object, Object> targetDataSources = new HashMap<>(5);
        Yaml yaml = new Yaml();
        try (InputStream in = this.getClass().getClassLoader().getResourceAsStream("datasource.yml")) {
            properties = (JSONObject) JSONObject.toJSON(yaml.load(in));
            JSONObject master = properties.getJSONObject("datasource").getJSONObject("master");
            JSONObject slave = properties.getJSONObject("datasource").getJSONObject("slave");

            // 设置主从数据源
            targetDataSources.putAll(buildDataSourcesMap("master", master));
            targetDataSources.putAll(buildDataSourcesMap("slave", slave));

            log.info("已加载主库数据源数量到内存中:{}", DataBaseNumCache.getAreaMasterDataBaseNumMap());
            log.info("已加载从库数据源数量到内存中:{}", DataBaseNumCache.getAreaSlaveDataBaseNumMap());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return targetDataSources;
    }

    private Map<Object, Object> buildDataSourcesMap(String type, JSONObject dataSourceInfos) {
        String dataSourceType = type.equals("master") ? DataSourceTypeConstant.MASTER_DB : DataSourceTypeConstant.SLAVE_DB;
        JSONArray list;
        Map<Object, Object> targetDataSources = new HashMap<>();
        for (String area : dataSourceInfos.keySet()) {
            list = dataSourceInfos.getJSONArray(area);
            for (int i = 0; i < list.size(); i++) {
                if (type.equals("master")) {
                    targetDataSources.put(area, initDruidDataSource(list.getJSONObject(i)));
                    DataBaseNumCache.getAreaMasterDataBaseNumMap().put(area, DataBaseNumCache.getAreaMasterDataBaseNumMap().getOrDefault(area, 0) + 1);
                } else {
                    targetDataSources.put(area + dataSourceType + i, initDruidDataSource(list.getJSONObject(i)));
                    DataBaseNumCache.getAreaSlaveDataBaseNumMap().put(area, DataBaseNumCache.getAreaSlaveDataBaseNumMap().getOrDefault(area, 0) + 1);
                }

            }
        }
        return targetDataSources;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);

        sqlSessionFactoryBean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath:/mappers/*Mapper.xml")
        );
        return sqlSessionFactoryBean.getObject();
    }
}
